import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { PayOrder } from 'src/payOrder/payOrder.entity';
import { VipInfoService } from 'src/vipInfo/vipInfo.service';
import { Repository, EntityManager } from 'typeorm';
import { PAY_NOTIFY_TYPE, ORDER_STATUS } from 'src/common/const/const';
import { genPayLogicSign } from 'src/common/utils/base';
import { PayNotificationDto } from 'src/payNotify/dto/payNotification';
import { convertTimestampToDatetimeFormat } from 'src/common/utils/base';
import { serviceInfoLog,serviceErrorLog } from "src/common/out/logger/access.logger";

@Injectable()
export class PayNotifyService {
    constructor(
        @InjectRepository(PayOrder)
        private payOrderRepository: Repository<PayOrder>,
        private readonly vipInfoService: VipInfoService,

    ) { }


    async handlePayNotification(payNotificationDto: PayNotificationDto) {
        // 验证签名
        const verifySuccess = this.verifySign(payNotificationDto)
        if (!verifySuccess) {
            return { success: false, message: "verify sign failed" }
        }
        // 根据通知类型，决定处理方法
        const notifyType = payNotificationDto.notify_type
        if (notifyType === PAY_NOTIFY_TYPE.ORDER_SUCCEED) {
            return this.handleSuccessType(payNotificationDto)
        }

        const errMsg = `no corresponding handle to notifyType: ${notifyType}`
        serviceErrorLog(errMsg)
        return { success: false, message: errMsg };
    }

    verifySign(payNotificationDto: PayNotificationDto) {
        const data = {
            "notify_type": payNotificationDto.notify_type,
            "project_name": payNotificationDto.project_name,
            "transaction_id": payNotificationDto.transaction_id,
            "out_trade_no": payNotificationDto.out_trade_no,
            "third_party_transaction_id": payNotificationDto.third_party_transaction_id,
            "pay_type": payNotificationDto.pay_type,
            "amount": payNotificationDto.amount,
            "order_status": payNotificationDto.order_status,
            "pay_time": payNotificationDto.pay_time,
        }
        const sign = genPayLogicSign(data)
        if (sign != payNotificationDto.sign) {
            return false;
        }
        return true;
    }

    async findPayOrder(entityManager: EntityManager, transactionId: string, outTradeNo: string) {
        // 使用悲观写锁
        return await entityManager.createQueryBuilder(PayOrder, 'payOrder')
            .where('payOrder.transactionId = :transactionId', { transactionId })
            .orWhere('payOrder.outTradeNo = :outTradeNo', { outTradeNo })
            .setLock('pessimistic_write')
            .getOne();
    }

    async handleSuccessType(payNotificationDto: PayNotificationDto) {
        serviceInfoLog("[handleSuccessType] begin");
        const { out_trade_no: transactionId, transaction_id: outTradeNo, third_party_transaction_id: thirdPartyTransactionId } = payNotificationDto;

        return await this.payOrderRepository.manager.transaction(async (entityManager: EntityManager) => {
            const payOrder = await this.findPayOrder(entityManager, transactionId, outTradeNo);
            if (!payOrder) {
                serviceErrorLog(`[handleSuccessType] error, payOrder not found, transactionId: ${transactionId}, outTradeNo: ${outTradeNo}`);
                return { false: false, message: `payOrder not found` };
            }

            if (payOrder.status === ORDER_STATUS.SUCCEED) {
                serviceInfoLog(`[handleSuccessType] Pay order has already succeeded, payNotificationDto: ${JSON.stringify(payNotificationDto)}`);
                return { success: true, message: "Pay order has already succeeded." };
            }

            if (payOrder.status === ORDER_STATUS.INIT) {
                try {
                    const payTime = convertTimestampToDatetimeFormat(payNotificationDto.pay_time);
                    const updateData = { status: ORDER_STATUS.SUCCEED, thirdPartyTransactionId: thirdPartyTransactionId, payTime: payTime };
                    // 更新支付订单
                    await entityManager.update(PayOrder, { transactionId: transactionId }, updateData);
                    // 处理vipInfo
                    await this.vipInfoService.handleVipInfoAfterPayment(entityManager, payOrder.userid, payOrder.goodsId);

                    serviceInfoLog(`[handleSuccessType] payOrder updated successfully, transactionId: ${transactionId}, updateData: ${JSON.stringify(updateData)}`);
                    return { success: true, message: "Pay order updated successfully." };
                } catch (error) {
                    serviceErrorLog(`[handleSuccessType] error updating payOrder, error: ${error.message}, payNotificationDto: ${JSON.stringify(payNotificationDto)}`)
                    throw error
                }
            }

            serviceErrorLog(`[handleSuccessType] error, payOrder status error, status: ${payOrder.status}, payNotificationDto: ${JSON.stringify(payNotificationDto)} `)
            return { success: false, message: `Pay order status error: ${payOrder.status}` };
        })
    }

    async handleFailType(payNotificationDto: PayNotificationDto) {
        serviceInfoLog("[handleFailType] begin")
        const { out_trade_no: transactionId, transaction_id: outTradeNo, third_party_transaction_id: thirdPartyTransactionId } = payNotificationDto
        return await this.payOrderRepository.manager.transaction(async (entityManager: EntityManager) => {
            const payOrder = await this.findPayOrder(entityManager, transactionId, outTradeNo)

            if (payOrder.status === ORDER_STATUS.FAILED) {
                serviceInfoLog(`[handleFailType], payOrder has already pay failed, payNotificationDto: ${JSON.stringify(payNotificationDto)}`)
                return { success: true, message: "Pay order has already failed." };
            }
            if (payOrder.status === ORDER_STATUS.INIT) {
                try {
                    const updateData = { status: ORDER_STATUS.FAILED, thirdPartyTransactionId: thirdPartyTransactionId }
                    // 更新支付订单
                    await entityManager.update(PayOrder, { transactionId: transactionId }, updateData);
                    serviceInfoLog(`[handleFailType] payOrder updated successfully, transactionId: ${transactionId}, updateData: ${JSON.stringify(updateData)}`)
                    return { success: true, message: "Pay order updated successfully." };
                } catch (error) {
                    serviceErrorLog(`[handleFailType] error updating payOrder, error: ${error.message}, payNotificationDto: ${JSON.stringify(payNotificationDto)}`)
                    return { success: false, message: `Error updating pay order: ${error.message}` };
                }
            }
            serviceErrorLog(`[handleFailType] error, payOrder status error, status: ${payOrder.status}, payNotificationDto: ${JSON.stringify(payNotificationDto)} `)
            return { success: false, message: `Pay order status error: ${payOrder.status}` };
        })
    }
}

